/*
 * marketsim-eclipsetrader
 *
 * Copyright (C) 2008-2011 Steve Phelps and John Cartlidge
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 */
/*
 *  (C) Victria Ltd. 2007
 */
/*
 * Copyright (c) 2004-2006 Marco Maccaferri and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Marco Maccaferri - initial API and implementation
 */

package victria.marketsim.eclipsetrader.view;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

import net.sourceforge.eclipsetrader.core.CorePlugin;
import net.sourceforge.eclipsetrader.core.ICollectionObserver;
import net.sourceforge.eclipsetrader.core.db.Event;
import net.sourceforge.eclipsetrader.core.db.PopupEvent;
import net.sourceforge.eclipsetrader.core.ui.dialogs.EventDetailsDialog;
import net.sourceforge.eclipsetrader.core.ui.internal.Messages;

import org.apache.log4j.Logger;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;

import victria.marketsim.core.BeanFactorySingleton;
import victria.marketsim.core.Market;
import victria.marketsim.event.MarketEvent;
import victria.marketsim.event.MarketEventListener;

public class ServerEventsView extends ViewPart implements
		MarketEventListener {
	public static final String VIEW_ID = "victria.marketsim.eclipsetrader.view.ServerEventsView"; //$NON-NLS-1$

	protected static ConcurrentLinkedQueue<MarketEvent> events
		= new ConcurrentLinkedQueue<MarketEvent>();
	
	protected boolean packed = false;

	Table table;

	Action removeSelectedAction;

	Action removeAllAction;

	SimpleDateFormat dateFormatter = new SimpleDateFormat("dd/MM/yyyy"); //$NON-NLS-1$

	SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$

	ViewEventDetailsDialog dialog;
	
	protected Market server;
	
	static Logger logger = Logger.getLogger(ServerEventsView.class);

	private Comparator comparator = new Comparator() {
		public int compare(Object arg0, Object arg1) {
			return ((Event) arg1).getDate().compareTo(((Event) arg0).getDate());
		}
	};

	private DisposeListener dialogDisposeListener = new DisposeListener() {
		public void widgetDisposed(DisposeEvent e) {
			dialog = null;
		}
	};

	/* (non-Javadoc)
	 * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite)
	 */
	public void init(IViewSite site) throws PartInitException {
		
		server = (Market) BeanFactorySingleton.getBean("marketService");
		server.addListener(this);
		
		IToolBarManager toolBarManager = site.getActionBars()
				.getToolBarManager();
		toolBarManager.add(new Separator("begin")); //$NON-NLS-1$
		toolBarManager.add(new Separator("group5")); //$NON-NLS-1$
		toolBarManager
				.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
		toolBarManager.add(new Separator("end")); //$NON-NLS-1$

		removeSelectedAction = new Action() {
			public void run() {
				TableItem[] selection = table.getSelection();
				for (int i = 0; i < selection.length; i++)
					CorePlugin.getRepository().delete(
							(Event) selection[i].getData());
			}
		};
		removeSelectedAction
				.setToolTipText(Messages.EventsView_RemoveActionTooltip);
		removeSelectedAction.setImageDescriptor(CorePlugin
				.getImageDescriptor("icons/elcl16/search_rem.gif")); //$NON-NLS-1$
		removeSelectedAction.setDisabledImageDescriptor(CorePlugin
				.getImageDescriptor("icons/dlcl16/search_rem.gif")); //$NON-NLS-1$
		removeSelectedAction.setEnabled(false);
		toolBarManager.appendToGroup("group5", removeSelectedAction); //$NON-NLS-1$
		removeAllAction = new Action() {
			public void run() {
				events.clear();
				updateView();
			}
		};
		removeAllAction
				.setToolTipText(Messages.EventsView_RemoveAllActionTooltip);
		removeAllAction.setImageDescriptor(CorePlugin
				.getImageDescriptor("icons/elcl16/search_remall.gif")); //$NON-NLS-1$
		removeAllAction.setDisabledImageDescriptor(CorePlugin
				.getImageDescriptor("icons/dlcl16/search_remall.gif")); //$NON-NLS-1$
		removeAllAction.setEnabled(false);
		toolBarManager.appendToGroup("group5", removeAllAction); //$NON-NLS-1$

		super.init(site);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
	 */
	public void createPartControl(Composite parent) {
//		server.addListener(this);
		Composite content = new Composite(parent, SWT.NONE);
		GridLayout gridLayout = new GridLayout();
		gridLayout.marginWidth = gridLayout.marginHeight = 0;
		gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
		content.setLayout(gridLayout);

		table = new Table(content, SWT.SINGLE | SWT.FULL_SELECTION);
		table.setHeaderVisible(true);
		table.setLinesVisible(false);
		table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		table.addMouseListener(new MouseAdapter() {
			public void mouseDoubleClick(MouseEvent e) {
				if (table.getSelectionIndex() != -1) {
					if (dialog == null) {
						Event event = (Event) table.getItem(
								table.getSelectionIndex()).getData();
						dialog = new ViewEventDetailsDialog(event,
								getViewSite().getShell());
						dialog.open();
					}
				}
			}
		});
		table.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				removeSelectedAction
						.setEnabled(table.getSelectionIndex() != -1);
			}
		});
		TableColumn column = new TableColumn(table, SWT.NONE);
		column.setText(Messages.EventsView_Date);
		column = new TableColumn(table, SWT.NONE);
		column.setText(Messages.EventsView_Time);
//		        column = new TableColumn(table, SWT.NONE);
//		        column.setText(Messages.EventsView_Security);
		column = new TableColumn(table, SWT.NONE);
		column.setText(Messages.EventsView_Message);

        parent.getDisplay().asyncExec(new Runnable() {
            public void run()
            {
				for (int i = 0; i < table.getColumnCount(); i++)
					table.getColumn(i).pack();
            }
        });
        
        updateView();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
	 */
	public void setFocus() {
		table.getParent().setFocus();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
	 */
	public void dispose() {
//		CorePlugin.getRepository().allEvents().removeCollectionObserver(this);
//		server.removeListener(this);
		super.dispose();
	}

	private void updateView() {
		table.removeAll();

		for (MarketEvent event : events) {
			TableItem tableItem = new TableItem(table, SWT.NONE, 0);
			tableItem.setText(0, dateFormatter.format(event.getTimeStamp()));
			tableItem.setText(1, timeFormatter.format(event.getTimeStamp()));
			//            tableItem.setText(2, event.getSecurity() != null ? event.getSecurity().getDescription() : ""); //$NON-NLS-1$
			tableItem.setText(2, event.toPrettyString());
			tableItem.setData(event);
		}

		        for (int i = 0; i < table.getColumnCount(); i++)
		            table.getColumn(i).pack();

		removeSelectedAction.setEnabled(table.getSelectionIndex() != -1);
		removeAllAction.setEnabled(table.getItemCount() != 0);
	}

	/* (non-Javadoc)
	 * @see net.sourceforge.eclipsetrader.core.ICollectionObserver#itemAdded(java.lang.Object)
	 */
	public void eventOccurred(final MarketEvent event) {

		logger.debug("Logging " + event);
		events.add(event);
		
		if (table.isDisposed()) {
			return;
		}
		
		table.getDisplay().asyncExec(new Runnable() {
			public void run() {
				if (table.isDisposed()) {
					logger.debug("table is disposed");
					return;
				}

				TableItem tableItem = new TableItem(table, SWT.NONE, 0);
				tableItem.setText(0, dateFormatter.format(event.getTimeStamp()));
				tableItem.setText(1, timeFormatter.format(event.getTimeStamp()));
				tableItem.setText(2, event.toPrettyString());
				tableItem.setData(event);
				
				if (!packed) {
					for (int i = 0; i < table.getColumnCount(); i++) {
						table.getColumn(i).pack();
					}
					if (events.size() > 5) {
						packed = true;
					}
				}
				
				logger.debug("tableItem = " + tableItem);


				removeSelectedAction
						.setEnabled(table.getSelectionIndex() != -1);
				removeAllAction.setEnabled(table.getItemCount() != 0);
			
				if (dialog != null)
					dialog.updateButtonStatus();
				
				
			}
		});
	}

	/* (non-Javadoc)
	 * @see net.sourceforge.eclipsetrader.core.ICollectionObserver#itemRemoved(java.lang.Object)
	 */
	public void itemRemoved(final Object o) {
		table.getDisplay().asyncExec(new Runnable() {
			public void run() {
				TableItem[] items = table.getItems();
				for (int i = 0; i < items.length; i++) {
					if (items[i].getData().equals(o))
						items[i].dispose();
				}

				for (int i = 0; i < table.getColumnCount(); i++)
					table.getColumn(i).pack();

				removeSelectedAction
						.setEnabled(table.getSelectionIndex() != -1);
				removeAllAction.setEnabled(table.getItemCount() != 0);
				if (dialog != null)
					dialog.updateButtonStatus();
			}
		});
	}

	public Table getTable() {
		return table;
	}

	/**
	 * View-aware event details dialog.
	 * <p>This object subclasses the standard event details dialog to hilight the currently
	 * viewed event.</p>
	 */
	class ViewEventDetailsDialog extends EventDetailsDialog {

		public ViewEventDetailsDialog(Event event, Shell parentShell) {
			super(event, parentShell);
		}

		/* (non-Javadoc)
		 * @see net.sourceforge.eclipsetrader.core.ui.dialogs.EventDetailsDialog#updateEvent()
		 */
		protected void updateEvent() {
			TableItem[] items = table.getItems();
			for (int i = 0; i < items.length; i++) {
				if (getEvent().equals(items[i].getData()))
					table.select(i);
			}
			super.updateEvent();
		}

		/* (non-Javadoc)
		 * @see org.eclipse.jface.window.Window#open()
		 */
		public int open() {
			dialog.setBlockOnOpen(false);
			int result = super.open();
			dialog.getShell().addDisposeListener(dialogDisposeListener);
			return result;
		}

		/* (non-Javadoc)
		 * @see net.sourceforge.eclipsetrader.core.ui.dialogs.EventDetailsDialog#updateButtonStatus()
		 */
		public void updateButtonStatus() {
			super.updateButtonStatus();
		}
	}
}
